package openai

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/slclub/glog"
	"github.com/slclub/go-tips"
	"io/ioutil"
	"math"
	"os"
	"os/exec"
	"strings"
)

type ChatGPTRecord struct{}

var CONFIG = map[string]any{
	"Path":        "chatgpt_record_logs/",
	"fileMaxLine": 1000000,
}

type LogItemField struct {
	Timestamp int64
	UserAgent string
	UID       string
	Smodel    string
	Question  string
	Answer    string
	IP        string
	date      string
}

func (this *AppGPT) SetRecordLog(params map[string]any) (err any) {
	recordJSON, _ := json.Marshal(params)
	recordString := string(recordJSON)
	record := ChatGPTRecord{}
	res := record.WriteFile(recordString)

	return res
}

func (this *AppGPT) GetRecordTotalDetail(parseStartData string, startTimestamp int64, parseEndData string, endTimestamp int64, diffDay int) (data map[string]any, err error) {
	record := ChatGPTRecord{}
	fileName := tips.String(CONFIG["Path"]) + "*.log"
	totalUvCmdStr := "cat " + fileName + " | awk -F ',\"uid\":\"|\",\"userAgent\":\"' '{print $2}' | uniq | wc -l"
	totalUvRes := tips.Int(strings.TrimSpace(record.ExecCommand(totalUvCmdStr)))

	totalPvCmdStr := "cat " + fileName + " | uniq -c | wc -l"
	totalPvRes := tips.Int(strings.TrimSpace(record.ExecCommand(totalPvCmdStr)))

	rangeCmdWhereStr := "$2 >=" + tips.String(startTimestamp) + " && $2 <= " + tips.String(endTimestamp)
	rangePvCmdStr := "cat " + fileName + " | awk -F ',\"timestamp\":|,\"uid\":' '{if ( " + rangeCmdWhereStr + " ) print $0}' | wc -l"
	rangePvRes := tips.Int(strings.TrimSpace(record.ExecCommand(rangePvCmdStr)))

	rangeUvCmdStr := "cat " + fileName + " | awk -F ',\"timestamp\":|,\"uid\":' '{if ( " + rangeCmdWhereStr + " ) print $0}' | awk -F ',\"uid\":\"|\",\"userAgent\":\"' '{print $2}' | uniq | wc -l"
	rangeUvRes := tips.Int(strings.TrimSpace(record.ExecCommand(rangeUvCmdStr)))

	rangeDateStr := parseStartData + " - " + parseEndData
	data = map[string]any{
		"total_pv": map[string]any{
			"label": "总共PV",
			"value": totalPvRes,
		},
		"total_uv": map[string]any{
			"label": "总共UV",
			"value": totalUvRes,
		},
		"range_pv": map[string]any{
			"label": "范围PV",
			"value": rangePvRes,
			"date":  rangeDateStr,
		},
		"range_day_average_pv": map[string]any{
			"label": "范围日均PV",
			"value": fmt.Sprintf("%.2f", float64(rangePvRes)/float64(diffDay)),
			"date":  rangeDateStr,
		},
		"range_uv": map[string]any{
			"label": "范围UV",
			"value": rangeUvRes,
			"date":  rangeDateStr,
		},
		"range_day_average_uv": map[string]any{
			"label": "范围日均UV",
			"value": fmt.Sprintf("%.2f", float64(rangeUvRes)/float64(diffDay)),
			"date":  rangeDateStr,
		},
	}
	return data, err
}

func (this *AppGPT) GetRecordList(pageNum int, pageSizeNum int, startTimestamp int64, endTimestamp int64) (list []any, err error) {
	page := tips.Any2Int64(pageNum)
	pageSize := tips.Any2Int64(pageSizeNum)

	startLineKey := tips.Any2Int64(page*pageSize - (pageSize - 1))
	endLineKey := tips.Any2Int64(page * pageSize)

	fileNumber := tips.Any2Int64(CONFIG["fileMaxLine"])
	// 根据startLineKey 判断开始文件名称
	startReadFileKey := tips.Any2Int64(math.Ceil(float64(startLineKey / fileNumber)))
	startReadFileName := startReadFileKey*fileNumber + 1

	// 根据endLineKey 判断结束文件名称
	c := tips.Any2Int64(float64(endLineKey % fileNumber))
	var endReadFileName int64
	endReadFileKey := tips.Any2Int64(math.Ceil(float64(endLineKey / fileNumber)))

	if c == 0 {
		endReadFileName = (endReadFileKey-1)*fileNumber + 1
	} else {
		endReadFileName = endReadFileKey*fileNumber + 1
	}

	var cmdStr string
	//var printStr string
	startFilePath := tips.String(CONFIG["Path"]) + tips.String(startReadFileName) + ".log"
	endFilePath := tips.String(CONFIG["Path"]) + tips.String(endReadFileName) + ".log"

	rangeCmdWhereStr := "$2 >=" + tips.String(startTimestamp) + " && $2 <= " + tips.String(endTimestamp)
	lineCmd := " | tail -n +" + tips.String(startLineKey) + " | head -n " + tips.String(pageSize)
	if startReadFileName == endReadFileName {
		//printStr = "执行命令行: tac " + startFilePath + " | awk -F ',\"timestamp\":|,\"uid\"' '{if ( " + rangeCmdWhereStr + " ) print $0}'" + lineCmd
		cmdStr = "tac " + startFilePath + " | awk -F ',\"timestamp\":|,\"uid\"' '{if ( " + rangeCmdWhereStr + " ) print $0}'" + lineCmd
	} else {
		//printStr = "执行命令行: tac " +startFilePath + endFilePath + " | awk -F ',\"timestamp\":|,\"uid\"' '{if ( " + rangeCmdWhereStr + " ) print $0}'" + lineCmd
		cmdStr = "tac " + startFilePath + endFilePath + " | awk -F ',\"timestamp\":|,\"uid\"' '{if ( " + rangeCmdWhereStr + " ) print $0}'" + lineCmd
	}
	//fmt.Println(printStr)

	record := ChatGPTRecord{}
	cmdRes := record.ExecCommand(cmdStr)

	tmpList := strings.Split(cmdRes, "\n")

	var logList []any
	var logItem LogItemField
	for _, value := range tmpList {
		if value == "" || value == "\n" {
			continue
		}
		_ = json.Unmarshal([]byte(value), &logItem)
		logList = append(logList, logItem)
	}

	return logList, err
}

func (this *AppGPT) GetRecordTotal() (total int64, err error) {
	record := ChatGPTRecord{}

	endFileNameCmd := "ls -t " + tips.String(CONFIG["Path"]) + " |head -n1|awk '{print $0}'"
	endFileNameStrRes := record.ExecCommand(endFileNameCmd)
	endFileNum := tips.Any2Int64(strings.Replace(strings.Replace(endFileNameStrRes, ".log", "", -1), "\n", "", -1))

	fileName := record.GetFilePath()
	cmdStr := "cat " + fileName + "| wc -l"
	totalStr := record.ExecCommand(cmdStr)
	currentFileNum := tips.Any2Int64(tips.Int(strings.TrimSpace(totalStr)))
	total = currentFileNum + endFileNum - 1
	if total < 0 {
		total = 0
	}

	return total, err
}

func (self *ChatGPTRecord) CheckFileExist(fileName string) bool {
	_, err := os.Stat(fileName)
	if os.IsNotExist(err) {
		return false
	}
	return true
}

func (self *ChatGPTRecord) ExecCommand(cmdStr string) (res string) {
	cmd := exec.Command("bash", "-c", cmdStr)

	//创建获取命令输出管道
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		glog.Errorf("Error:can not obtain stdout pipe for command:%s\n", err)
		return
	}

	//执行命令
	if err = cmd.Start(); err != nil {
		glog.Errorf("Error:The command is err,", err)
		return
	}

	//读取所有输出
	cmdRes, err := ioutil.ReadAll(stdout)
	if err != nil {
		glog.Errorf("ReadAll Stdout:", err.Error())
		return
	}

	if err = cmd.Wait(); err != nil {
		glog.Errorf("wait:", err.Error())
		return
	}

	return string(cmdRes)
}

func (self *ChatGPTRecord) GetFilePath() (filePath string) {
	fileNameCommandStr := "ls -t " + tips.String(CONFIG["Path"]) + " |head -n1|awk '{print $0}'"
	fileNameCmdRes := self.ExecCommand(fileNameCommandStr)
	fileName := strings.TrimSpace(fileNameCmdRes)

	if fileName == "" {
		fileName = "1.log"
	}

	path := tips.String(CONFIG["Path"])
	commandStr := "cat " + path + fileName + " | wc -l"
	fileLineCmdRes := self.ExecCommand(commandStr)
	fileNum := tips.Int(strings.TrimSpace(fileLineCmdRes))

	// 检测当前文件存储是否超过1万行，如果超过，新创建文件记录
	if fileNum >= tips.Int(CONFIG["fileMaxLine"]) {
		//fmt.Println("超过")
		newName := tips.String(tips.Int(strings.Replace(fileName, ".log", "", -1)) + tips.Int(CONFIG["fileMaxLine"]))
		return path + newName + ".log"
	}

	//fmt.Println("未超过")
	return path + fileName
}

func (self *ChatGPTRecord) WriteFile(params string) (res any) {
	fileName := self.GetFilePath()
	//fmt.Println(fileName)

	dir := tips.String(CONFIG["Path"])
	if err := os.MkdirAll(dir, 0755); os.IsExist(err) {
		//fmt.Println("文件夹存在")
	} else {
		//fmt.Println("文件夹不存在")
	}

	var file *os.File
	var err error
	if self.CheckFileExist(fileName) {
		file, err = os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND, 0666)
	} else {
		file, err = os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0666)
	}

	if err != nil {
		//fmt.Println("文件打开失败",err)
		return "log文件打开失败"
	}

	//及时关闭file句柄
	defer file.Close()

	//写入文件时，使用带缓存的 *Writer
	write := bufio.NewWriter(file)
	_, err = write.WriteString(params + " \n")
	if err != nil {
		//fmt.Println("使用缓存失败")
		return "使用缓存失败"
	}

	//Flush将缓存的文件真正写入到文件中
	err = write.Flush()
	if err != nil {
		//fmt.Println("缓存写入文件失败")
		return "缓存写入文件失败"
	}

	return true
}
